<?php
// +----------------------------------------------------------------------+
// | Author:  Evgeny Leontev <eleontev@gmail.com>                         |
// | Copyright (c) 2005 Evgeny Leontev                                    |
// +----------------------------------------------------------------------+
// | This source file is free software; you can redistribute it and/or    |
// | modify it under the terms of the GNU Lesser General Public           |
// | License as published by the Free Software Foundation; either         |
// | version 2.1 of the License, or (at your option) any later version.   |
// |                                                                      |
// | This source file is distributed in the hope that it will be useful,  |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
// | Lesser General Public License for more details.                      |
// +----------------------------------------------------------------------+

/**
 * ResultCache is a class used to cache result of your script(function).
 * On first execution of function, execute the function and write returned  
 * data to file(cache), on second execution and more, read data from file.
 * You can specify "how long" cache is valid.
 *
 * SIMPLE EXAMPLE:
 * $sql = "your complex query";
 * function yourFunc($sql) {
 *     $result = mysql_query($sql) or die (db_error());
       while($row = mysql_fetch_assoc($result)){
 *         $array[] = $row;
 *     }
 *     return $array;
 * }
 * 
 * $cache = new ResultCache();
 * $cache->setSerialize(true);
 * $cache->setUserFuncVars('yourFunc', $sql);
 * $data = $cache->getData('cache_id');
 *
 *
 * @version 1.0
 * @since 13/08/2003
 * @author Evgeny Leontiev <eleontev@gmail.com>
 * @access public
 */

class ResultCache
{	
	var $cache_dir;      			// directory where cache stored
	var $file_ext;		        	// file extension, in which cache will be saved
	var $f_name;
	var $f_param;
	
	var $do_serialize = false;		// serialize or not data, 
									// if returned data is array you should serialize it
	var $refresh = false;			// use it for global refresh
	var $exp_time = 0;				// time in minute after that cache will expiered, 
									// 0 or false = never expiered 

	
    /**
     * Class constructor
     *
	 * @param    string    $cache_dir    (optional) directory where cache files will be
	 * @param    int       $exp_time     (optional) time in minutes after that cache will expired	 
     * @access   public
     */
	function ResultCache($cache_dir = false, $exp_time = 0) {
		$this->cache_dir = $cache_dir;
		$this->exp_time = $exp_time;
	}

	
   /**
	* setSerialize -- set behavior for reading and wring cache.
	*
	* If true data will be serialized before writing cache and unserialized after reading cache
	* Can be used to store resultset from sql query, like array
	*
	* @param     boolean  $set true/false
	* @access    public      
	*/
	function setSerialize($set = true) {
		$this->do_serialize = $set;
	}
	
	
   /**
	* setUserFuncVars -- set vars for using in call_user_func_array.
	*
	* to call method for $f_name use array(&$obj, "method_name") syntax.
	*
	* @param    string    $f_name      function name
	* @param    mixed     $f_param     string or array, parameters for function	
	* @access    public      
	*/
	function setUserFuncVars($f_name, $f_param = array()) {
		$this->f_name = $f_name;
		$this->f_param = $f_param;
	}
	
	
   /**
	* getData -- get cache or raw data.
	*
	* Get data using function - $f_name or from cache if any
	* if no cache or $refresh = true, write new cache
	*
	* @param    string    $cache_id    id for current cache, use md5 if complex string
	* @param    boolean   $refresh     true if need to refresh data
	*
	* @return   string    data generated by function or from cache
	* @access   public
	*/
	function getData($cache_id, $refresh = false) {
		
		$cache_id = $this->cache_dir . $cache_id . $this->file_ext;
	
		$data = false;
		if($this->exp_time) {
			@$exp_time = (time() - filemtime($cache_id))/60; 
			if($this->exp_time > floor($exp_time)) {
				$data = $this->read($cache_id);
			}
		} else {
			$data = $this->read($cache_id);
		}
		
		if($this->refresh || $refresh || !$data) {
			$data = call_user_func_array($this->f_name, $this->f_param);
		
			if($this->do_serialize) { $data = serialize($data); }
			$this->write($cache_id, $data);
		}
		
		if($this->do_serialize) { $data = unserialize($data); }
		return $data;
	}
	
	
   /**
	* read -- get data from file.
	*
	* @param    string    $filename    filename to read
	*
	* @return   string    data from file or false on failure
	* @access   public
	*/
	function read($filename) {

		$data = false;
		if($fp = @fopen($filename, "rb")) {
			$data = fread($fp, filesize($filename));
			fclose($fp);
		}
		return $data;
	}


   /**
	* write -- write data to file.
	*
	* @param    string    $filename    filename to write
	* @param    string    $data        data to write
	* 
	* @return   boolean   true/false
	* @access   public
	*/
	function write($filename, $data) {	
	
		$ret = false;
		if($fp = @fopen($filename, 'ab')) {
			flock($fp, LOCK_EX);
			ftruncate ($fp, 0);
			fputs($fp, $data);
			fflush($fp);
			flock($fp, LOCK_UN);
			fclose($fp);
			$ret = true;
		}
		return $ret;
	}
	
} // <-- end
?>